package JUC.old;

/**
 * 需求:线程隔离
 * 在多线程并发的场景下，每个线程中的变量都是相互独立
 * 线程A :设置(变量1)  获取(变量1)
 * 线程B :设置(变量2)  获取(变量2)
 * ThreadLocal :
 * 1. set()将变量绑定到当前线程中
 * 2. get() :获取当前线程绑定的变量
 * 2. remove() :删除当前线程绑定的变量
 *
 * synchronized
 * 同步机制采用以时间换空间的方式,只提供了一份变量，让不同的线程排队访问侧重点
 * 多个线程之间访问资源的同步
 *
 * ThreadLocal
 * 采用以空间换时间的方式，
 * 为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰
 * 多线程中让每个线程之间的数据相互隔离
 * 1.传递数据:保存每个线程绑定的数据,在需要的地方可以直接获取,避免参数直接传递带来的代码耦合问题
 * 2.线程隔离:各线程之间的数据相互隔离却又具备扣发性,避免同步方式带来的性能损失
 *
 * JDK8之前
 *   每个ThreadLocal维护了一个ThreadLocalMap  里面存了每个Thread的对象
 *
 * JDK8时
 *    每个Thread(线程)维护了一个ThreadLocalMap  里面存了每个ThreadLocal的对象
 *
 *
 * ThreadLocal.ThreadLocalMap
 *     默认大小16  每次扩容*2   负载因子位2/3（超了会执行rehash一次全表的扫描清理工作）
 *     每个结点都是一个Entry
 *     Entry继承了WeakReference<ThreadLocal< ?>>  弱引用
 *     如果hash冲突了 使用线性探测法（大小为16时）（  14-》15-》0-》1...  ）
 *     （该方法一次探测下一个地址,直到有空的地址后插入,若整个空间都找不到空余的地址,则产生溢出）
 *
 * 内存泄漏的情况中.都有两个前提:
 * 1.没有手动删除这个Entry
 * 2. CurrentThread（当前线程）依然运行
 * 避免内存泄漏：
 * 1.使用完ThreadLocal,调用其remove方法删除对应的Entry
 * 2.使用完ThreadLocal，当前Thread也随之运行结束
 *
 * 使用弱引用的好处：
 * 在ThreadLocalMap中的set/getEntry方法中,
 * 会对key为null (也即是ThreadLocal为null )进行判 断,
 * 如果为null的话,那么是会对value置为null的。
 * 这就多了一层保障   就算忘记了remove  它也会在下一次执行时删除掉
 */
public class ThreadLocalDemo {

    ThreadLocal<String> t1 = new ThreadLocal<>();
    private String str;

    public static void main(String[] args) {
        ThreadLocalDemo threadLocalDemo = new ThreadLocalDemo();
        System.out.println("---不加锁不加ThreadLocal  " +
                "可能会线程1添加信息后信息2get到了出现错误---" +
                "因为他们用的是一个对象-----");
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                threadLocalDemo.setT1(Thread.currentThread().getName() + "的数据");
                System.out.println("------------");
                System.out.println(Thread.currentThread().getName() + "--->" + threadLocalDemo.getT1());
            },"线程"+i).start();
        }
    }

    private String getT1(){
        return t1.get();
//        return str;
    }

    private void setT1(String str){
        t1.set(str);
//        this.str=str;
    }
}

